﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;

namespace CodeDomHelper.CodeDom
{


    public enum extension
    {
        cs,
        vb,
        js
    }

    public static partial class Helper
    {


        public static string Extract(this CodeObject code, extension extension)
        {
            return Extract(code, extension.ToString());
        }

        public static string Extract(this CodeObject code, string extensionName)
        {
            CodeDomProvider provider = GetProvider(extensionName);
            return ExtractCode(code, provider);
        }

        public static string Extract(this CodeObject code, CodeDomProvider provider)
        {
            return ExtractCode(code, provider);
        }


        #region Extract with provider

        private static string ExtractCode<T>(T code, CodeDomProvider provider)
            where T : CodeObject
        {
            
            CodeStatement v1 = code as CodeStatement;
            if (v1 != null)
                return Extract(v1, provider);

            CodeTypeDeclaration v2 = code as CodeTypeDeclaration;
            if (v2 != null)
                return Extract(v2, provider);

            CodeCompileUnit v3 = code as CodeCompileUnit;
            if (v3 != null)
                return Extract(v3, provider);

            CodeExpression v4 = code as CodeExpression;
            if (v4 != null)
                return Extract(v4, provider);

            CodeNamespace v5 = code as CodeNamespace;
            if (v5 != null)
                return Extract(v5, provider);

            CodeTypeMember v6 = code as CodeTypeMember;
            if (v6 != null)
                return Extract(v6, provider);

            throw new NotImplementedException(typeof(T).ToString());

        }

        private static string Extract(CodeTypeDeclaration code, CodeDomProvider provider)
        {

            StringBuilder s = new StringBuilder();

            using (MemoryStream fs = new MemoryStream())
            using (StringWriter w = new StringWriter(s))
                provider.GenerateCodeFromType(code, w, new CodeGeneratorOptions());

            return s.ToString();
        }
        private static string Extract(CodeCompileUnit code, CodeDomProvider provider)
        {
            StringBuilder s = new StringBuilder();

            using (MemoryStream fs = new MemoryStream())
            using (StringWriter w = new StringWriter(s))
                provider.GenerateCodeFromCompileUnit(code, w, new CodeGeneratorOptions());

            return s.ToString();
        }
        private static string Extract(CodeExpression code, CodeDomProvider provider)
        {
            StringBuilder s = new StringBuilder();

            using (MemoryStream fs = new MemoryStream())
            using (StringWriter w = new StringWriter(s))
                provider.GenerateCodeFromExpression(code, w, new CodeGeneratorOptions());

            return s.ToString();
        }
        private static string Extract(CodeNamespace code, CodeDomProvider provider)
        {
            StringBuilder s = new StringBuilder();

            using (MemoryStream fs = new MemoryStream())
            using (StringWriter w = new StringWriter(s))
                provider.GenerateCodeFromNamespace(code, w, new CodeGeneratorOptions());

            return s.ToString();
        }
        private static string Extract(CodeStatement code, CodeDomProvider provider)
        {
            StringBuilder s = new StringBuilder();

            using (MemoryStream fs = new MemoryStream())
            using (StringWriter w = new StringWriter(s))
                provider.GenerateCodeFromStatement(code, w, new CodeGeneratorOptions());

            return s.ToString();
        }
        private static string Extract(CodeTypeMember code, CodeDomProvider provider)
        {
            StringBuilder s = new StringBuilder();

            using (MemoryStream fs = new MemoryStream())
            using (StringWriter w = new StringWriter(s))
                provider.GenerateCodeFromMember(code, w, new CodeGeneratorOptions());

            return s.ToString();
        }

        #endregion

        private static CodeDomProvider GetProvider(string extensionName)
        {
            string language = CodeDomProvider.GetLanguageFromExtension(extensionName);
            CodeDomProvider provider = CodeDomProvider.CreateProvider(language);
            return provider;
        }

    }

}
